/*
Created on Sept. 28th 2005
(C) 2005 
@author Michael J Ocean

This program is free software; you can redistribute it and/or
modify it under the terms of Version 2 of the GNU General Public 
License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package sxe.sensors;

import java.io.ByteArrayInputStream;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import snbenchlib.XML;
import snobject.snObject;


public abstract class GenericSensor {

	public static final String TYPE_VIDEO = "Video";
	public static final String TYPE_IMAGE = "Image";
	public static final String TYPE_IMAGE_PTZ = "PTZ_Image";
	public static final String TYPE_AUDIO = "Audio";
	public static final String TYPE_KISMET = "WiFi";
	public static final String TYPE_UNKNOWN = "Unknown";
	public static final String TYPE_TEMPERATURE = "Temperature";
	public static final String TYPE_CLOCK = "Clock";
	public static final String TYPE_ALL = "ALL";
	
	public static final String STATE_PREINIT = "NOT INITIALIZED";
	public static final String STATE_INIT = "INITIALIZED";
	public static final String STATE_INUSE = "IN USE";
	public static final String STATE_FAILED = "FAILED";

	public static final String tagName = "device";
	
	/* should initialize the sensor for use
	 * - should set state to one of the above STATE_*
	 * - should set ID
	 * return true if ready or false if unavailable
	 */
	abstract public boolean initializeSensor();
	abstract public boolean isAlive();
	abstract public snObject getData(Object oParam);
	abstract public boolean shutDown();
	
	abstract public String GetInfoXML();
	
	protected String GetInfoXML(String s){
		StringBuffer b = new StringBuffer();
		b.append("<" + tagName + " " + 
			"id=\"" + getID() + "\" " + 
			"xmlns=\"" + XML.XMLNS + "\" " + 
			"state=\"" + getState() + "\" " +
			"type=\"" + getType() + "\" " +
			"uri=\"" + getURI() + "\">\n");
		
		b.append(s);		
		b.append("</" + tagName + ">\n");
		return b.toString();
	}
	
	protected String m_state;
	protected String m_type;
	protected String m_id;
	protected String m_uri;
	

	public GenericSensor(){
		m_state = GenericSensor.STATE_PREINIT;
		m_type = GenericSensor.TYPE_UNKNOWN;
		m_id = SensorDetector.ProduceID();
		m_uri = m_type + "/" + m_id;
				
		SensorDetector.RegisterID(m_id);
	}
	public String getState(){
		return m_state;
	}
	
	public String getType(){
		return m_type;
	}
	
	public String getID(){
		return m_id;
	}	
	
	public void setID(String newID){
		m_id = newID;
	}	
	
	public String getURI(){
		return m_uri;
	}	

	/**
	 * Factory style method to produce an instance of a specific class derived
	 * from GenericSensor (e.g., PTZSensor, ImageSensor, and so on)
	 * 
	 * @param SensorType - the Type of the sensor (see GenericSensor.TYPE_*)
	 * @param SensorID - The ID of the sensor (may be ANY, or other wildcards)
	 * @param uri - the URI where the sensor resource can be found (may be null)
	 * @param state - the state of the resource (may be null)
	 * @return
	 * @throws UnknownSensorTypeException
	 */
	public static GenericSensor InstantiateSpecific(String SensorType,
													String SensorID,
													String uri,
													String state) throws UnknownSensorTypeException {
		GenericSensor result = null;

		if(SensorID==null)
			throw new NullPointerException("GenericSensor.InstantiateSpecific requires a sensor ID to be specified (or wildcard keywords)");
		if(SensorType==null)
			throw new NullPointerException("GenericSensor.InstantiateSpecific requires a sensor type to be specified (from GenericSensor.TYPE_??)");

		if(GenericSensor.TYPE_IMAGE.equalsIgnoreCase(SensorType)){
			result = new ImageSensor();
		}else if(GenericSensor.TYPE_IMAGE_PTZ.equalsIgnoreCase(SensorType)){
			result = new PTZSensor();
		}else if(GenericSensor.TYPE_KISMET.equalsIgnoreCase(SensorType)){
			result = new KismetSensor();
		}else if(GenericSensor.TYPE_TEMPERATURE.equalsIgnoreCase(SensorType)){
			result = new TempSensor();
		}else if(GenericSensor.TYPE_CLOCK.equalsIgnoreCase(SensorType)){
			result = new ClockSensor();
		}else{
			throw new UnknownSensorTypeException("The sensor type [" + SensorType + "] is unsupported in GenericSensor.InstantiateSpecific");
		}

		result.m_id = SensorID;
		result.m_type = SensorType;
		
		if (state != null){
			result.m_state = state;
		}			
		if (uri == null){
			result.m_uri = uri;
		}
		return result;
	}
	
    public static GenericSensor Parse(String xml)
    {
    	Document d = null;
    	ByteArrayInputStream bis = new ByteArrayInputStream(xml.getBytes());
    	try {
			d = snbenchlib.XML.getDocumentBuilder().parse(bis);
		} catch (java.io.IOException e) {
		    System.err.println(e.getMessage());
		    return null;
		} catch (org.xml.sax.SAXException e) {
		    System.err.println(e.getMessage());
		    return null;
		}
		
		d.normalize();
		Element root = d.getDocumentElement();

    	return xmlParse(root);
    }

    public static GenericSensor xmlParse(Element root)
    {    			
		GenericSensor result = null;

		try{
			if (root.getTagName() != tagName)
			    throw new step.parse.SyntaxError("Sensor root node [" + root.getTagName() + "] must be [" + tagName + "]");
			String id = root.getAttribute("id");
			if (id == null){
				System.err.println("Can not parse Sensor as ID is missing");
				throw new step.parse.SyntaxError("Sensor root node [" + root.getTagName() + "] must have an ID !");
			}
	
			String state=null;
			String type=null;
			String uri = null;
			
			state = root.getAttribute("state");
			type = root.getAttribute("type");
			uri = root.getAttribute("uri");
			
			if (type == null){
				System.err.println("Can not parse Sensor as type is missing");
				throw new step.parse.SyntaxError("Sensor root node [" + root.getTagName() + "] must have a type !");
			}
			
			result = InstantiateSpecific(type, id, uri, state);
		
		}catch(step.parse.SyntaxError se){
			se.printStackTrace();
		}catch(UnknownSensorTypeException uste){
			uste.printStackTrace();
		}
		
		return result;
    }
	public String GetMinimalXML() {
		return GetInfoXML("");
	}
}
